package com.xbongbong.paas.service.impl;


import com.alibaba.dingtalk.openapi.exception.OApiException;
import com.alibaba.dingtalk.openapi.helper.AuthHelper;
import com.alibaba.dingtalk.openapi.helper.Env;
import com.alibaba.dingtalk.openapi.helper.ServiceHelper;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.constant.TimeConstant;
import com.xbongbong.paas.domain.entity.PaasAppEntity;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.model.PaasAppModel;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.service.CompanyService;
import com.xbongbong.paas.service.PackageService;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.UserVO;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.enums.PackageErrorEnum;
import com.xbongbong.pro.enums.PackageTypeEnum;
import com.xbongbong.pro.enums.errorcodes.StatisticsServicesErrorCodeEnum;
import com.xbongbong.pro.enums.menu.enums.SystemAppMenuEnum;
import com.xbongbong.pro.enums.permission.enums.ProPermissionAliasEnum;
import com.xbongbong.pro.packageInfo.pojo.CheckPackagePojo;
import com.xbongbong.pro.packageInfo.pojo.vo.BasePackageInfoVO;
import com.xbongbong.pro.packageInfo.pojo.vo.CheckPackageVO;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.DingBundleLogEntity;
import com.xbongbong.saas.model.DingBundleLogModel;
import com.xbongbong.sys.domain.entity.CompanyEntity;
import com.xbongbong.sys.domain.entity.FeeCompanyEntity;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.model.CompanyModel;
import com.xbongbong.sys.model.DepartmentModel;
import com.xbongbong.sys.model.FeeCompanyModel;
import com.xbongbong.sys.model.UserModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 *
 * @author 魏荣杰
 * @date 2019/2/13 16:58
 * @since v1.0
 * @version v1.0
 */
@Service("companyService")
public class CompanyServiceImpl implements CompanyService {

    private static final Logger LOG = LoggerFactory.getLogger(CompanyServiceImpl.class);

    @Resource
    private UserModel userModel;
    @Resource
    private DepartmentModel departmentModel;
    @Resource
    private CompanyModel companyModel;
    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    private AuthHelper authHelper;
    @Resource
    private PackageService packageService;
    @Resource
    private DingBundleLogModel dingBundleLogModel;
    @Resource
    private PaasAppModel paasAppModel;
    @Resource
    private FeeCompanyModel feeCompanyModel;

    @Override
    public Integer getCorpRealUserNum(String corpid) {

        Map<String,Object> param= new HashMap<>(16);
        param.put("corpid", corpid);
        param.put("del", 0);
        //公司人数
        Integer realUserNum=userModel.getEntitysCount(param);
//		TODO 待优化
        Integer depNum = departmentModel.getEntitysCount(param);
        if (depNum > BasicConstant.MAX_REAL_DEP_NUM) {
            realUserNum = BasicConstant.MAX_REAL_USER_NUM + 100;
        }
        return realUserNum;
    }

    @Override
    public boolean checkCorpRealNum(String corpid) throws XbbException {
        Map<String,Object> param= new HashMap<>(16);
        param.put("corpid", corpid);
        param.put("del", 0);
        //公司人数
        Integer realUserNum=userModel.getEntitysCount(param);
        if (realUserNum > BasicConstant.MAX_REAL_USER_NUM) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224010, StatisticsServicesErrorCodeEnum.API_ERROR_224010.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.EMPLOYEE_NUM), BasicConstant.MAX_REAL_USER_NUM);
        }
        Integer depNum = departmentModel.getEntitysCount(param);
        if (depNum > BasicConstant.MAX_REAL_DEP_NUM) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224010,
                    StatisticsServicesErrorCodeEnum.API_ERROR_224010.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.DEPARTMENT_NUM), BasicConstant.MAX_REAL_DEP_NUM);
        }
        return true;
    }



    /**
     * 更新单个公司的company表数据
     *
     * @param updateCorpid 公司id
     * @param suiteTokenPerm
     * @author kaka
     * @date 2016年7月27日 下午3:01:56
     */
    @Override
    public CompanyEntity updateCompanyInfo(String updateCorpid, String suiteTokenPerm) {
        String permanent_code = paasRedisHelper.getValue("permanentcode", updateCorpid);

        /*
         * 拿到permanent_code（永久授权码）后，向钉钉服务器获取企业的基本信息并插入库或更新数据库记录
         */
        JSONObject authInfo = ServiceHelper.getAuthInfo(suiteTokenPerm,
                Env.SUITE_KEY, updateCorpid, permanent_code);

        String authAgentId;
        try {
            authAgentId = authHelper.getAgentId(updateCorpid, Env.DING_XBB_APP_ID);
        } catch (OApiException e1) {
            LOG.error("获取agentId失败", e1);
            return null;
        }

        CompanyEntity company = companyModel.getByKeyIgnoreDel(updateCorpid);
        boolean insertCompany = false;
        if (company == null) {
            company = new CompanyEntity();
            insertCompany = true;
            // 前面一步对企业进行了激活，所以这里讲入库的企业设为正常状态，同步不要修改status
            company.setStatus(1);
            // 将公司del置为0，同步不要修改status
            company.setDel(0);
        }

        company.formatCompanyData(authInfo);
        company.setPermanentCode(permanent_code);

        // 设置agentId
        company.setAgentId(authAgentId);
        try {
            if (insertCompany) {
                companyModel.insert(company);
            } else {
                companyModel.update(company);
            }
            return company;
        } catch (Exception e) {
            LOG.error("获取agentId失败", e);
            return null;
        }
    }

    @Override
    public String getPermanentCode(String corpId){
        String permanentCode = paasRedisHelper.getValue("permanentcode", corpId);

        if (StringUtil.isEmpty(permanentCode)) {
            CompanyEntity companyFromDB = companyModel.getByKeyIgnoreDel(corpId);
            if(companyFromDB != null) {
                permanentCode = companyFromDB.getPermanentCode();
            }
            if(permanentCode == null) {
                return null;
            } else {
                paasRedisHelper.setValuePermanent("permanentcode", corpId, permanentCode);
            }
        }
        return permanentCode;
    }


    @Override
    public CheckPackageVO checkPackage(String corpid) {
        Map<String,Object> param=new HashMap<>();
        param.put("corpid", corpid);
        param.put("del", 0);
        // 使用人数
        Integer corpUserNum = userModel.getEntitysCount(param);
        return checkPackage(corpid, corpUserNum);
    }

    @Override
    public CheckPackageVO checkPackage(String corpid, Integer corpUserNum) {
        BasePackageInfoVO basePackageInfoVO = null;
        try {
            basePackageInfoVO = packageService.getBasePackageInfoFromRedis(corpid);
        } catch (XbbException e) {
            String showMsg = I18nMessageUtil.getMessage(I18nStringConstant.COMPANY_INFO_ABNORMAL);
            return getCheckPackageVO(PackageErrorEnum.UNKNOWN, showMsg);
        }

        //没有套餐信息则提示错误
        if (StringUtil.isEmpty(basePackageInfoVO.getFeeName())) {
            String showMsg = String.format(I18nMessageUtil.getMessage(I18nStringConstant.NO_PACKAGE_INFO),
                    basePackageInfoVO.getCorpName(), corpid, StringConstant.SUPPORT_HOTLINE);

            return getCheckPackageVO(PackageErrorEnum.UNKNOWN, showMsg);
        }

        //公司名称
        final String corpName = basePackageInfoVO.getCorpName();
        Integer isTrail = basePackageInfoVO.getIsTrail();
        String mainCorpid = basePackageInfoVO.getMainCorpid();
        //0表示未购买过的用户（免费用户）
        Integer vipNum = basePackageInfoVO.getVipNum();
        String feeName = basePackageInfoVO.getFeeName();
        String scale = basePackageInfoVO.getScale();
        String industry = basePackageInfoVO.getIndustry();
        // 免费套餐数量
        Integer feeNum = basePackageInfoVO.getFeeNum();
        //套餐开始时间
        Long startTime = basePackageInfoVO.getFeeStartTime() == null ? 0 : basePackageInfoVO.getFeeStartTime();
        startTime = DateTimeUtil.getTodayInt(startTime);

        //套餐结束时间
        Long endTime = basePackageInfoVO.getFeeEndTime() == null ? 0 : basePackageInfoVO.getFeeEndTime();
        //套餐许可使用人数
        int feeUserNum = basePackageInfoVO.getFeeUserNum() == null ? 0 : basePackageInfoVO.getFeeUserNum();

        CheckPackagePojo checkPackagePojoPojo = new CheckPackagePojo("", PackageErrorEnum.NORMAL);
        // 是否为免费版　
        Integer isFree = Objects.isNull(basePackageInfoVO.getIsFree()) ? 1 : basePackageInfoVO.getIsFree();
        //套餐类型
        Integer feeType = basePackageInfoVO.getFeeType();

        //   notStarted           数量限制、即将到期提醒                 end
        //                  ---------------------------------
        //套餐未开始
        if (notStarted(startTime, checkPackagePojoPojo)){
            //expireType = 11
            return getCheckPackageVO(corpName, feeName, checkPackagePojoPojo, isFree, isTrail, mainCorpid, scale, industry, vipNum, feeNum, feeType);
        }

        //套餐已结束
        if (end(endTime, vipNum, corpName, checkPackagePojoPojo)){
            //expireType = 4 expireType = 8
            return getCheckPackageVO(corpName, feeName, checkPackagePojoPojo, isFree, isTrail, mainCorpid, scale, industry, vipNum, feeNum, feeType);
        }

        //人数超过套餐限制
        if (userNumOver(corpUserNum, feeUserNum, corpName, checkPackagePojoPojo)) {
            //expireType = 9
            return getCheckPackageVO(corpName, feeName, checkPackagePojoPojo, isFree, isTrail, mainCorpid, scale, industry, vipNum, feeNum, feeType);
        }

        //即将到期提醒
        if (expiredReminder(endTime, vipNum, corpName, checkPackagePojoPojo)) {
            //expireType = 3 expireType = 7
            return getCheckPackageVO(corpName, feeName, checkPackagePojoPojo, isFree, isTrail, mainCorpid, scale, industry, vipNum, feeNum, feeType);
        }

        checkPackagePojoPojo.setShowMsg("");
        checkPackagePojoPojo.setPackageErrorEnum(PackageErrorEnum.NORMAL);

        return getCheckPackageVO(corpName, feeName, checkPackagePojoPojo, isFree, isTrail, mainCorpid, scale, industry, vipNum, feeNum, feeType);
    }
    
    /**
     * 判断群功能是否已经关闭了
     * @param corpid
     * @param userVO
     * @return true关掉，false没有关掉
     */
    @Override
    public Boolean flagCloseGroup(String corpid, UserVO userVO) {
        CompanyEntity companyEntity = companyModel.getByKey(corpid);
        Boolean groupCloseFlag = true;
        try {
            PaasAppEntity paasAppEntity = paasAppModel.getByAlias(SystemAppMenuEnum.BUNDLE.getAlias(),corpid);
            if ( Objects.isNull(paasAppEntity) || Objects.equals(paasAppEntity.getEnable(),0)) {
                return true;
            }
            if ( !userVO.getPermSet().contains(ProPermissionAliasEnum.SALE_BUNALE_ADD.getAlias()) ) {
                return true;
            }
            // 先赋值认为是还没有看过
            DingBundleLogEntity dingBundleLogEntity = dingBundleLogModel.getEntityByUserId(userVO.getUserId(),corpid);
            if ( Objects.isNull(dingBundleLogEntity)) {
                groupCloseFlag = false;
            }
            //检查套餐是否合适:见过+套餐正确
            if ( groupCloseFlag && (Objects.equals(companyEntity.getFeeType(), PackageTypeEnum.ADVANCED.getType())
                    || Objects.equals(companyEntity.getFeeType(), PackageTypeEnum.ULTIMATE.getType())) ) {
                groupCloseFlag = true;
            }
            //查看是否有权限
            if ( groupCloseFlag && userVO.getPermSet().contains(ProPermissionAliasEnum.SALE_BUNALE_ADD.getAlias()) ) {
                groupCloseFlag = false;
            }
        } catch (Exception e) {
            LOG.info("是否开启报错",e);
        }
        return groupCloseFlag;
    }
    
    @Override
    public JSONObject handlePackageErrorInfo(UserEntity loginUser, Integer errorType) {
        JSONObject packageInfo = new JSONObject();
        packageInfo.put("type", errorType);
        if(Objects.equals(PackageErrorEnum.USER_COUNT_OVER.getCode(), errorType)) {
            boolean isAdmin = Objects.equals(BasicConstant.ONE, loginUser.getIsAdmin());
            if(!isAdmin) {
                Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                param.put(StringConstant.CORPID, loginUser.getCorpid());
                param.put(StringConstant.DEL, DelEnum.NORMAL.getDel());
                param.put("isAdmin", BasicConstant.ONE);
                List<UserEntity> adminList = userModel.findEntitys(param);
                StringBuffer userNames = new StringBuffer();
                // 只取三个
                if (adminList.size() > 5) {
                    adminList = adminList.subList(0, 5);
                }
                for (UserEntity entity : adminList) {
                    if (userNames.length() > 0) {
                        userNames.append("、" + entity.getName());
                    } else {
                        userNames.append(entity.getName());
                    }
                }
                packageInfo.put("adminNames", userNames);
            }
            packageInfo.put("isAdmin", isAdmin);
        }
        return packageInfo;
    }
    
    /**
     * 检查当前公司是否有授权开通群服务的小程序，并检查是否有查看的权限
     *
     * @param corpid
     * @param userId
     * @return
     */
    @Override
    public Integer checkDingtalkBundle(String corpid, String userId) {
        
        dingBundleLogModel.getEntityByUserId(userId,corpid);
        return null;
    }

    @Override
    public long getFeeEndTime(String corpid) {
        // 默认-1表示公司套餐无效
        long feeEndTime = -1L;
        String feeEndTimeStr = paasRedisHelper.getValue(RedisPrefixConstant.COMPANY_FEE_END_TIME, corpid);
        if (StringUtil.isEmpty(feeEndTimeStr)) {
            // 缓存不命中
            FeeCompanyEntity feeCompany = feeCompanyModel.getHistoryActiveFeeCompany(corpid);
            if (feeCompany != null) {
                feeEndTime = feeCompany.getEndTime();
            }
            // 设置缓存
            paasRedisHelper.setValue(RedisPrefixConstant.COMPANY_FEE_END_TIME, corpid, feeEndTime, TimeConstant.TEN_MINUTE_DURATION);
        } else {
            // 缓存命中
            feeEndTime = Long.parseLong(feeEndTimeStr);
        }
        return feeEndTime;
    }

    private CheckPackageVO getCheckPackageVO(PackageErrorEnum packageErrorEnum, String showMsg) {
        CheckPackageVO checkPackageVO = new CheckPackageVO();
        checkPackageVO.setIsActive(packageErrorEnum.getIsActive());
        checkPackageVO.setExpireType(packageErrorEnum.getCode());
        checkPackageVO.setShowMsg(showMsg);
        return checkPackageVO;
    }


    private CheckPackageVO getCheckPackageVO(String corpName, String feeName, CheckPackagePojo checkPackagePojo, Integer isFree, Integer isTrail, String mainCorpid, String scale,
                                             String industry, Integer vipNum, Integer feeNum, Integer feeType) {
        CheckPackageVO checkPackageVO = new CheckPackageVO();
        checkPackageVO.setCorpName(corpName);
        checkPackageVO.setFeeName(feeName);
//        isVipVO.setIsVip();
        checkPackageVO.setShowMsg(checkPackagePojo.getShowMsg());
        checkPackageVO.setIsActive(checkPackagePojo.getPackageErrorEnum().getIsActive());
        checkPackageVO.setExpireType(checkPackagePojo.getPackageErrorEnum().getCode());
        checkPackageVO.setIsFree(isFree);
        checkPackageVO.setIsTrail(isTrail);
        checkPackageVO.setMainCorpid(mainCorpid);
        checkPackageVO.setScale(scale);
        checkPackageVO.setIndustry(industry);
        checkPackageVO.setVipNum(vipNum);
        checkPackageVO.setFeeNum(feeNum);
        checkPackageVO.setFeeType(feeType);
        return checkPackageVO;
    }

    /**
     * 套餐未开始
     * @param startTime 开始时间
     * @param checkPackagePojo
     * @return true 表示套餐未开始 false套餐已开始
     * 创建时间 2019/4/10 2:04 PM
     * 修改时间 2019/4/10 2:04 PM
     * @author chy
     * @since v1.0
     * @version v1.0
     */
    private boolean notStarted(Long startTime, CheckPackagePojo checkPackagePojo) {
        Long today = DateTimeUtil.getTodayInt();

        if (today >= startTime) {
            return false;
        }

        String startTimeStr = DateTimeUtil.getStringEpochSecond(startTime, DateTimeUtil.SDFDate);
        checkPackagePojo.setShowMsg(String.format(I18nMessageUtil.getMessage(StringConstant.MESSAGE_NOT_STARTED), startTimeStr, StringConstant.SUPPORT_HOTLINE));
        checkPackagePojo.setPackageErrorEnum(PackageErrorEnum.NOT_STARTED);
        return true;
    }

    /**
     * 套餐已结束
     * @param endTime 结束时间
     * @param vipNum 购买次数
     * @param corpName 公司名
     * @param checkPackagePojo
     * @return
     * 创建时间 2019/4/10 2:04 PM
     * 修改时间 2019/4/10 2:04 PM
     * @author chy
     * @since v1.0
     * @version v1.0
     */
    private boolean end(Long endTime, Integer vipNum, String corpName, CheckPackagePojo checkPackagePojo) {
        Long today = DateTimeUtil.getTodayInt();

        if (today <= endTime) {
            return false;
        }

        String endTimeStr = DateTimeUtil.getStringEpochSecond(endTime, DateTimeUtil.SDFDate);
        if(Objects.equals(vipNum, 0)){
            //免费用户
            checkPackagePojo.setShowMsg(String.format(I18nMessageUtil.getMessage(StringConstant.MESSAGE_FREE_EXPIRED), corpName, endTimeStr, StringConstant.SUPPORT_HOTLINE));
            checkPackagePojo.setPackageErrorEnum(PackageErrorEnum.FREE_EXPIRE);
        }else{
            //付费用户
            checkPackagePojo.setShowMsg(String.format(I18nMessageUtil.getMessage(StringConstant.MESSAGE_VIP_EXPIRED), corpName, endTimeStr, StringConstant.SUPPORT_HOTLINE));
            checkPackagePojo.setPackageErrorEnum(PackageErrorEnum.VIP_EXPIRE);
        }
        return true;
    }

    /**
     * 人数超过套餐限制
     * @param corpUserNum 公司使用人数
     * @param feeUserNum 套餐限制人数
     * @param corpName 公司名
     * @param checkPackagePojo
     * @return
     * 创建时间 2019/4/10 2:13 PM
     * 修改时间 2019/4/10 2:13 PM
     * @author chy
     * @since v1.0
     * @version v1.0
     */
    private boolean userNumOver(Integer corpUserNum, Integer feeUserNum, String corpName, CheckPackagePojo checkPackagePojo) {

        if (corpUserNum <= feeUserNum) {
            return false;
        }
        checkPackagePojo.setShowMsg(String.format(I18nMessageUtil.getMessage(StringConstant.MESSAGE_USER_OVER), corpName, feeUserNum, corpUserNum));
        checkPackagePojo.setPackageErrorEnum(PackageErrorEnum.USER_COUNT_OVER);
        return true;
    }

    /**
     * 提醒即将到期
     * @param endTime 结束时间
     * @param vipNum 购买次数
     * @param corpName 公司名
     * @param checkPackagePojo
     * @return true 即将到期提醒 false不提醒
     * 创建时间 2019/4/10 2:41 PM
     * 修改时间 2019/4/10 2:41 PM
     * @author chy
     * @since v1.0
     * @version v1.0
     */
    private boolean expiredReminder(Long endTime, Integer vipNum, String corpName, CheckPackagePojo checkPackagePojo) {

        checkPackagePojo.setShowMsg("yes");

        //免费的提醒时间，即将到期1、3、7天时提醒
        List<Integer> freeReminderDays = Arrays.asList(1, 3, 7);
        //付费的提醒时间，即将到期1、3、7、15、30天时提醒
        List<Integer> vipReminderDays = Arrays.asList(1, 3, 7, 15, 30);

        Long today = DateTimeUtil.getTodayInt();
        //剩余时间
        int leftTime = (endTime.intValue() - today.intValue())/86400 + 1;
        String endTimeStr = DateTimeUtil.getStringEpochSecond(endTime, DateTimeUtil.SDFDate);
        //未购买过
        if (Objects.equals(vipNum, 0)) {
            if (freeReminderDays.contains(leftTime)) {
                checkPackagePojo.setShowMsg(String.format(I18nMessageUtil.getMessage(StringConstant.MESSAGE_FREE_EXPIRED_REMINDER),
                        corpName, leftTime, endTimeStr, StringConstant.SUPPORT_HOTLINE));
                checkPackagePojo.setPackageErrorEnum(PackageErrorEnum.FREE_WILL_EXPIRE);
                return true;
            }
        } else {
            if (vipReminderDays.contains(leftTime)) {
                checkPackagePojo.setShowMsg(String.format(I18nMessageUtil.getMessage(StringConstant.MESSAGE_VIP_EXPIRED_REMINDER),
                        corpName, leftTime, endTimeStr, StringConstant.SUPPORT_HOTLINE));
                checkPackagePojo.setPackageErrorEnum(PackageErrorEnum.VIP_WILL_EXPIRE);
                return true;
            }
        }
        return false;
    }
}
